from os import listdir
from bpy.types import PropertyGroup
from ...addon.paths import FluidLabPaths
from os.path import join, exists, splitext
from bpy.props import EnumProperty, FloatProperty, IntProperty, BoolProperty
from ...libs.functions.get_common_vars import get_common_vars
from ...libs.functions.libraries import read_fluid_preset



class FluidLab_PG_FluidPresets(PropertyGroup):
    
    """ context.scene.fluidlab.fluid_presets.x """
    
    items = []

    @staticmethod
    def load_items(self, context):

        if len(self.items) == 0: # <- para evitar estar constantemente leyendo del disco
            
            default_path = join(FluidLabPaths.LIBS, "fluid_presets")
            if exists(default_path):
                presets = [f for f in listdir(default_path) if f.endswith(".json")]
                for f_name in presets:
                    base_name = splitext(f_name)[0]
                    # print(base_name)
                    item = (base_name.upper(), base_name.replace("_", " ").title(), "")
                    if item not in self.items:
                        self.items.append(item)
    
        return self.items
    
    def presets_update(self, context):

        fluid_presets = get_common_vars(context, get_fluid_presets=True)
        filename = fluid_presets.presets.lower() + ".json"

        default_path = join(FluidLabPaths.LIBS, "fluid_presets")
        file = join(default_path, filename)

        # Seteamos la ui con los valores del json:
        def set_ui_data(data_dict):
            for slug, value in data_dict.items():
                setattr(fluid_presets, slug, value)
        
        # fuerzo la lectura del preset.json en lugar de el que esta guardado en wm (porque si fue editado, no se reflejará)
        wm = context.window_manager
        if filename in wm:
            del wm[filename]

        # el data de los json:
        emission_data = read_fluid_preset(context, filename, file, "emission_props")
        physics_data = read_fluid_preset(context, filename, file, "physics_props")
        springs_data = read_fluid_preset(context, filename, file, "springs_props")

        if emission_data:
            set_ui_data(emission_data)
        
        if physics_data:
            set_ui_data(physics_data)

        if springs_data:
            set_ui_data(springs_data)

            
    presets: EnumProperty(
        name="Presets",
        description="Preconfigured Settings for Fliud Settings > Physics",
        items=lambda self, context: self.load_items(self, context),
        update=presets_update
    )

    #--------------------------------------------------------------------------------------------------------------
    # Para crear nuestros propios presets:
    #--------------------------------------------------------------------------------------------------------------
    
    def edit_preset_update(self, context):
        # Si no se a guardado el preset y salimos de modo edicion, establezco el mismo preset para actualizar la ui:
        if not self.edit_preset:
            self.presets = self.presets


    edit_preset: BoolProperty(name="Edit", description="Edit Preset", default=False, update=edit_preset_update)

    # emission_props:
    size_random: FloatProperty(name="Size Random", description="Render Scale Random", min=0, max=1, default=0)

    # physics_props:
    timestep: FloatProperty(name="Timestep", description="The simulation timestep per frame (seconds per frame)", default=0.04, soft_min=0.01, min=0, soft_max=10.0, max=100.0, precision=3)
    subframes: IntProperty(name="Subframes", description="Subframes to simulate for improved stability and finer granularity simulation (dt = timestep / (subframes + 1))", min=0, max=1000, default=4)
    use_adaptive_subframes: BoolProperty(name="Adaptive Subframe", description="Automatically set the number of subframes", default=False)
    courant_target: FloatProperty(name="Adaptive Subframe Threshold", description="The relative distance a particle can move before requiring more subframes (target Courant number); 0.01 to 0.3 is the recomended range", min=0, max=10, default=0.2, precision=3)
    mass: FloatProperty(name="Mass", description="Mass of the particles", default=0.1, min=0, soft_min=0.01, max=100000, unit='MASS', precision=4)
    use_multiply_size_mass: BoolProperty(name="Multiply by size", description="Multiply mass by particle size", default=False)
    stiffness: FloatProperty(name="Stiffness", description="How incomprensible the fluid is (speed of sound)", min=0, soft_max=10, max=1000.0, default=0.5, precision=4)
    linear_viscosity: FloatProperty(name="Viscosity", description="Linear Viscosity", min=0, soft_max=10, max=100.0, default=1, precision=4)
    drag_factor: FloatProperty(name="Drag", default=0.05, min=0, max=1)
    damping: FloatProperty(name="Damping", default=0.05, min=0, max=1)
    use_size_deflect: BoolProperty(name="Size Deflect", description="Use particle's size in deflection", default=False)
    repulsion: FloatProperty(name="Repulsion Factor", description="How strongly the fluid tries to keep from clustering (factor of stiffness)", min=0, soft_max=2, max=100.0, default=1, precision=3)
    stiff_viscosity: FloatProperty(name="Stiff Viscosity", description="Creates viscosity for expanding fluid", min=0, soft_max=2, max=100.0, default=0.1, precision=3)
    fluid_radius: FloatProperty(name="Radius", default=1, min=0, soft_max=2, max=20)
    rest_density: FloatProperty(name="Rest Density", description="Fluid rest density", min=0, soft_max=2, max=10000.0, default=1, precision=3)
    
    # springs_props:
    spring_force: FloatProperty(name="Force", default=0, min=0, soft_max=10, max=100.0)
    use_viscoelastic_springs: BoolProperty(name="Viscoelastic Springs", description="Use viscoelastic springs instead of Hooke's springs", default=False,)
    yield_ratio: FloatProperty(name="Elastic Limit", default=0.1, min=0, max=1)
    plasticity: FloatProperty(name="Plasticity", default=0.1, min=0, max=100.0)
    use_initial_rest_length: BoolProperty(name="Initial Length", description="Use inital length as spring rest length instead of 2 * per particle size", default=False)
    spring_frames: IntProperty(name="Spring Frames", description="Create springs for this number of frames since particles birth (0 is always)", default=0, min=0, max=100)
    use_factor_rest_length: BoolProperty(name="Factor Rest Length", description="Spring rest length as spring rest length instead of 2 * per particle size", default=True)
    rest_length: FloatProperty(name="Rest Length", default=1, min=0, max=2)